#include"memorypool.h"

memorypool::memorypool() : start_pool(nullptr), end_pool(nullptr), locker_()
{
    MemoryIndex_.clear();
    MemoryIndex_.reserve(sizeof MemorySize);
    for(auto &si : MemorySize)
    {
        std::shared_ptr<MemoryList>sk(new MemoryList);
        sk->nexthead = nullptr;
        MemoryIndex_.push_back(std::move(sk));
    }
}

memorypool::~memorypool()
{
    MemoryList *tmp, *sol;
    for(auto &si : MemoryIndex_)
    {
        tmp = si.get()->nexthead;
        while(tmp)
        {
            sol = tmp->nexthead;
            free(tmp);
            tmp = sol;
        }
    }
    MemoryIndex_.clear();
}

char* memorypool::refill(size_t size, int &num)
{
    char* tmp = start_pool;
    size_t remain = end_pool - start_pool;
    if(remain >= num*size)
    {
        start_pool += num*size;
        return tmp;
    }
    else if(remain >= size)
    {
        start_pool += size;
        num = 1; 
        if(start_pool == end_pool)
            start_pool = end_pool = nullptr;
        return tmp;
    }

    if(start_pool)
        pushte(static_cast<void*>(start_pool), remain);
    
    start_pool = static_cast<char*>(malloc((num+2)*size));
    if(start_pool)
    {
        end_pool = start_pool + (num+2)*size;
        tmp = start_pool;
        start_pool += num*size;
        return tmp;
    }
    else
        printf("mallocfalse\n");
    exit(0);
    // int n = (size - 1) / BasicUnit + 1;
    // for(n; n < sizeof MemorySize; n++)
    // {
    //     if(MemoryIndex_[n])
    //     {
    //         tmp = static_cast<char*>(task((n + 1) * BasicUnit));
    //         pushte(static_cast<void*>(tmp), (n + 1) * BasicUnit-size);
    //         tmp += (n + 1) * BasicUnit - size;
    //         num = 1;
    //         return tmp;
    //     }
    // }
    return nullptr;
}

void memorypool::push(void* recycle, size_t size)
{
    MutexLockGuard los(locker_);
    // pid_t curpid = locker_.gettid();
    // bool st = false;
    // if((locker_.holder_ != 0 && curpid != locker_.holder_) || locker_.holder_ == 0)
    // {
    //     locker_.lock();
    //     st = true;
    // }
    size = (size-1)/BasicUnit;
    memset((void*)recycle, 0, (size+1)*BasicUnit);
    MemoryList* tmp = MemoryIndex_[size].get()->nexthead;
    if(tmp)
    {
        MemoryIndex_[size].get()->nexthead = static_cast<MemoryList*>(recycle);
        static_cast<MemoryList*>(recycle)->nexthead = tmp;
    }
    else
        MemoryIndex_[size].get()->nexthead = static_cast<MemoryList*>(recycle);
    // if(st)
    //     locker_.unlock();
}


void memorypool::pushte(void* recycle, size_t size)
{
    size = (size-1)/BasicUnit;
    memset((void*)recycle, 0, (size+1)*BasicUnit);
    MemoryList* tmp = MemoryIndex_[size].get()->nexthead;
    if(tmp)
    {
        MemoryIndex_[size].get()->nexthead = static_cast<MemoryList*>(recycle);
        static_cast<MemoryList*>(recycle)->nexthead = tmp;
    }
    else
        MemoryIndex_[size].get()->nexthead = static_cast<MemoryList*>(recycle);
}


void* memorypool::task(size_t size)
{
    MutexLockGuard sop(locker_);
    int n = (size - 1)/BasicUnit;
    if(n<sizeof MemorySize)
    {
        if(MemoryIndex_[n].get()->nexthead)
        {
            MemoryList* tmp = MemoryIndex_[n].get()->nexthead;
            MemoryIndex_[n].get()->nexthead = tmp->nexthead;
            memset(tmp, '\0', (n+1)*BasicUnit);
            return  static_cast<void*>(tmp);
        }
        int num = 3;
        char* tmp = refill((n+1)*BasicUnit, num);
        if(num == 3)
        {
            pushte(static_cast<void*>(tmp), (n+1)*BasicUnit);
            tmp += (n+1)*BasicUnit;
            pushte(static_cast<void*>(tmp), (n+1)*BasicUnit);
            tmp += (n+1)*BasicUnit;
            memset(tmp, '\0', (n+1)*BasicUnit);
            return static_cast<void*>(tmp);
        }
        memset(tmp, '\0', (n+1)*BasicUnit);
        return static_cast<void*>(tmp);
    }
    return nullptr;
}